package com.ndp.fb.mq.service.schedulerservice.adpublish;

import com.alibaba.dubbo.config.annotation.Reference;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.ndp.fb.enums.publish.PublishResultType;
import com.ndp.fb.enums.publish.PublishStatus;
import com.ndp.fb.fbagent.service.AdCreativeFBService;
import com.ndp.fb.model.fbagent.param.APIPriority;
import com.ndp.fb.model.fbagent.param.ApiCallBackTarget;
import com.ndp.fb.model.fbagent.param.adcreative.AdCreativeParam;
import com.ndp.fb.model.fbagent.param.adcreative.ObjectStorySpec;
import com.ndp.fb.model.fbagent.result.common.FBSingleId;
import com.ndp.fb.mongo.api.PublishCacheMongoService;
import com.ndp.fb.rdb.api.*;
import com.ndp.fb.rdb.model.AdCreative;
import com.ndp.fb.rdb.model.BaseAdLevel;
import com.ndp.fb.rdb.model.PublishBatch;
import com.ndp.fb.redis.model.AdCreativeLevel;
import com.ndp.fb.util.ThreadPool;
import com.restfb.DefaultJsonMapper;
import com.restfb.JsonMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;

/**
 * 创意创建服务
 * Created by hunk.qin on 2015/3/12.
 */
@Component
public class PublishAdCreativeService extends PublishBase {

    public static final String BATCH_ID = "batchId";
    public static final String AD_CREATIVE_KEY = "adCreativeKey";
    private static final String AD_TYPE = "adCreative";
    private static Logger logger = LoggerFactory.getLogger(PublishAdCreativeService.class);


    @Reference
    private PublishBatchRdbService publishBatchRdbService;

    @Reference
    private AdCreativeFBService adCreativeFBService;

    @Reference
    private FbUserRdbService fbUserRdbService;

    @Reference
    private PublishResultRecordRdbService publishResultRecordRdbService;

    @Reference
    private PublishResultDetailRdbService publishResultDetailRdbService;

    @Reference
    private AdCreativeRdbService adCreativeRdbService;

    @Autowired
    private PublishCacheMongoServiceFailover publishCacheMongoService;



    /**
     * 创意发布
     * @param batchId
     */
    @Override
    public void publish(Long batchId, String nextLevelIndexs, BaseAdLevel preLevel) {
        publishBatchRdbService.updatePublishStatusById(batchId, PublishStatus.PUBLISHING.getCode());
        publishByCache(batchId);
    }

    /**
     * 创意创建回调
     */
    @Override
    public void callback(Map<String, String> equipment, Object fbSingleId) {
        ThreadPool.execute(() -> {
            try {
                Long batchId = Long.valueOf(equipment.get(BATCH_ID));
                String adCreativeKey = equipment.get(AD_CREATIVE_KEY).toString();
                String adCreativeLevelStr=publishCacheMongoService.findCacheBlockByTypeAndKey(batchId,PublishCacheMongoService.CREATIVE,adCreativeKey);
                AdCreativeLevel adCreativeLevel=JSONObject.parseObject(adCreativeLevelStr,AdCreativeLevel.class);

                PublishStatus publishStatus;
                Long adCreativeId = null;
                String exception = null;
                PublishResultType publishResultType;
                if (fbSingleId instanceof FBSingleId) {
                    adCreativeId = ((FBSingleId) fbSingleId).getId();
                    publishStatus = PublishStatus.SUCCEED;
                    publishResultType = PublishResultType.adCreativeSuccess;
                } else {
                    exception = fbSingleId.toString();
                    publishStatus = PublishStatus.FAIL;
                    publishResultType = PublishResultType.adCreativeFail;
                    logger.error("publishAdCreativeCallback->fb fail:" + exception);
                }
                //4-1 修改adCreativeLevel的status 1 发布成功  2 发布失败
                adCreativeLevel.setStatus(publishStatus.getCode());

                if (publishStatus== PublishStatus.SUCCEED) {
                    adCreativeLevel.setAdCreativeId(adCreativeId);
                    saveAdCreative(adCreativeLevel);
                    publishCacheMongoService.fillFbId(batchId,adCreativeKey,String.valueOf(adCreativeId),PublishCacheMongoService.CREATIVE);
                }
                publishCacheMongoService.updateStatus(batchId,adCreativeKey,publishStatus.getCode(),PublishCacheMongoService.CREATIVE);
                savePublishResult(adCreativeLevel, publishResultType, exception,AD_TYPE);
                logger.info("PublishAdCreativeCallBackJob->publishAdCreativeCallBack->AdCreative创建成功回调结束!");
            }catch (Exception e){
                logger.error("创意发布出现异常>>>>>", e);
            }

        });
    }

    @Override
    PublishResultDetailRdbService getPublishResultDetailRdbService() {
        return this.publishResultDetailRdbService;
    }

    @Override
    PublishResultRecordRdbService getPublishResultRecordRdbService() {
        return this.publishResultRecordRdbService;
    }

    private void saveAdCreative(AdCreativeLevel adCreativeLevel) {
        AdCreative adCreative = new AdCreative();
        adCreative.setAdCreativeId(adCreativeLevel.getAdCreativeId());
        adCreative.setFbAccountId(Long.parseLong(adCreativeLevel.getActAccountId().replace("act_", "")));
        adCreative.setFbConnectionObjectId(adCreativeLevel.getFbConnectionObjectId());
        String json = JSONObject.toJSONString(adCreativeLevel.getObjectStorySpec());

        JsonMapper jsonMapper = new DefaultJsonMapper();
        com.ndp.fb.model.fbagent.result.adcreative.ObjectStorySpec objectStorySpec = JSON.parseObject(json, com.ndp.fb.model.fbagent.result.adcreative.ObjectStorySpec.class);
        adCreative.setObjectStorySpec(jsonMapper.toJson(objectStorySpec, true));
        adCreative.setImageMd5(adCreativeLevel.getImageMd5());
        adCreative.setVideoMd5(adCreativeLevel.getVideoMd5());
        adCreative.setProductConfId(adCreativeLevel.getProductConfigurationId());
        adCreative.setPublishBatchId(adCreativeLevel.getPublishBatchId());
        adCreativeRdbService.save(adCreative);
        logger.info("AdCreative CallBack  Save ad_creative Success.");
    }

    private void publishByCache(Long batchId) {
        //每次都取最新的 accessToken
        AdCreativeLevel adCreativeLevel=null;
        try {
            PublishBatch publishBatch = publishBatchRdbService.findById(batchId);
            if(checkBatch(batchId,publishBatch)) return;
            String accessToken = fbUserRdbService.getTokenByUserId(publishBatch.getUserId());
            String creativeCacheStr = publishCacheMongoService.findCacheBlockByType(batchId, PublishCacheMongoService.CREATIVE);
            Map <String,AdCreativeLevel> adCreativeLevelMap= JSONObject.parseObject(creativeCacheStr,
                    new TypeReference<HashMap<String,AdCreativeLevel>>(){});
            for (Map.Entry<String, AdCreativeLevel> creativeLevelEntry : adCreativeLevelMap.entrySet()) {
                if(creativeLevelEntry.getValue().getStatus()==PublishStatus.WAIT_PUPLISH.getCode()
                        ||creativeLevelEntry.getValue().getStatus()==PublishStatus.FAIL.getCode()){
                    adCreativeLevel = creativeLevelEntry.getValue();
                    AdCreativeParam param = new AdCreativeParam();
                    param.setAccessToken(accessToken);
                    param.setFbAccountId(Long.valueOf(adCreativeLevel.getActAccountId().substring(4)));
                    param.setApiPriorityCode(APIPriority.CreateAdCreative.getCode());
                    param.setApiCallbackTargetType(ApiCallBackTarget.AdPublish.AdCreative.getTargetType());
                    ObjectStorySpec objectStorySpec = creativeLevelEntry.getValue().getObjectStorySpec();
                    param.setObjectStorySpec(objectStorySpec);
                    param.setResultClass(FBSingleId.class);
                    param.setUrlTags(adCreativeLevel.getUrlTags());
                    param.setProductSetId(adCreativeLevel.getProductSetId());
                    param.setCallBack(true);
                    //需要回调传递的参数
                    Map<String, String> equip = new HashMap<>();
                    equip.put(BATCH_ID, batchId + "");
                    equip.put(AD_CREATIVE_KEY, creativeLevelEntry.getKey());
                    param.setEquipment(equip);
                    adCreativeFBService.createAdCreative(param);
                }

            }
        }catch (Exception e){
            logger.error(e.getMessage(),e);
            savePublishResult(adCreativeLevel, PublishResultType.adCreativeFail, e.getMessage(),AD_TYPE);
        }
    }
}
